/*
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace panda::intrinsics {

// Autogenerated file -- DO NOT EDIT!
% Runtime::intrinsics.each do |intrinsic|
%   params = intrinsic.impl_signature.args.each_with_index.map {|cpp_type, index| cpp_type + " " + "arg#{index}" }
%   params = params.unshift("[[maybe_unused]] Method* /* unused */")
%   entrypoint = intrinsic.name + "EntryPoint"
// NOLINTNEXTLINE(misc-definitions-in-headers)
<%= intrinsic.impl_signature.ret %> <%= entrypoint %>(<%= params.join(", ") %>) {  // NOLINT
%   nargs = intrinsic.impl_signature.args.size
%   arg_list = (0...nargs).map { |i| "arg#{i}" }.join(", ")
%   ret_type = intrinsic.impl_signature.ret
%   if ret_type == 'void'
    <%= intrinsic.impl %>(<%= arg_list %>);
%   else
    return <%= intrinsic.impl %>(<%= arg_list %>);
% end
}

% end

// NOLINTNEXTLINE(readability-function-size,misc-definitions-in-headers)
bool Initialize() {
    Runtime *runtime = Runtime::GetCurrent();
    ClassLinker *class_linker = runtime->GetClassLinker();

    auto spaces = runtime->GetOptions().GetLoadRuntimes();

    std::string_view space;

% Runtime::intrinsics.each do |intrinsic|
    space = std::string_view("<%= intrinsic.space %>");
    if (std::find(spaces.begin(), spaces.end(), space) != spaces.end()) {
        auto mutf8_name = reinterpret_cast<const uint8_t *>("<%= get_object_descriptor(intrinsic.class_name) %>");
        auto klass = class_linker->GetClass(mutf8_name);
        if (klass == nullptr) {
            LOG(ERROR, RUNTIME) << "Cannot find class '" << mutf8_name << "'";
            return false;
        }
        mutf8_name = reinterpret_cast<const uint8_t *>("<%= intrinsic.method_name %>");

        Method::Proto proto;
        auto &shorty = proto.GetShorty();

%   types = [intrinsic.signature.ret] + intrinsic.signature.args
%   types.each do |t|
        shorty.emplace_back(panda_file::Type::TypeId::<%= get_shorty_type(t) %>);
%     if object_type?(t)
        proto.GetRefTypes().emplace_back("<%= get_object_descriptor(t) %>");
%     end
%   end

        auto method = klass->GetDirectMethod(mutf8_name, proto);
        if (method == nullptr) {
            LOG(ERROR, RUNTIME) << "Cannot find method '<%= intrinsic.class_name %>.<%= intrinsic.method_name %>'";
            return false;
        }
        method->SetIntrinsic(Intrinsic::<%= intrinsic.enum_name %>);
%       entrypoint = intrinsic.name + "EntryPoint"
        method->SetCompiledEntryPoint(reinterpret_cast<const void *>(<%= entrypoint %>));
    }
% end
    return true;
}

}  // namespace panda::intrinsics

% Runtime::intrinsics.uniq { |i| i.impl }.each do |intrinsic|
%   next if !intrinsic.need_abi_wrapper?
%   namespace, _, funcname = intrinsic.impl.rpartition('::')
namespace <%= namespace %> {
%   params = intrinsic.impl_signature.args.each_with_index.map {|cpp_type, index| cpp_type + " " + "arg#{index}" }
<%= intrinsic.impl_signature.ret %> <%= funcname %>(<%= params.join(", ") %>) {  // NOLINT
%   nargs = intrinsic.impl_signature.args.size
%   arg_list = (0...nargs).map do |i|
%     if intrinsic.impl_signature.args[i] == intrinsic.orig_impl_signature.args[i]
%       "arg#{i}"
%     else
%       "static_cast<#{intrinsic.orig_impl_signature.args[i]}>(arg#{i})"
%     end
%   end
%   arg_list = arg_list.join(", ")
%   ret_type = intrinsic.orig_impl_signature.ret
%   if ret_type == 'void'
    <%= intrinsic.orig_impl %>(<%= arg_list %>);
%   else
    return <%= intrinsic.orig_impl %>(<%= arg_list %>);
%   end
}
}  // namespace <%= namespace %>

% end
